﻿using RayDen.Library.Components.Surface;
using RayDen.Library.Core;
using RayDen.Library.Core.Primitives;

namespace RayEngine.Spectral.Entities.Brdfs
{
    public class AlloyBrdf : BrdfBase
    {
        public override BrdfType Type
        {
            get { return BrdfType.Glossy; }
        }

        public RgbSpectrum Krefl, Kdiff;

        public RgbSpectrum KdiffOverPI;
        public float exponent;
        public float R0;
        public bool reflectionSpecularBounce;
        public AlloyBrdf(float exp, float schlickTerm, bool reflSpecularBounce)
            : base()
        {
            R0 = schlickTerm;
            exponent = 1f / (exp + 1f);

            reflectionSpecularBounce = reflSpecularBounce;
        }

        public override void F(ShadePointInfo pt, out IColorType fs, BrdfType types = BrdfType.Diffuse)
        {
            float c = 1f - Vector.Dot(ref pt.IncomingDirection, ref pt.ShadingNormal);
            float Re = R0 + (1f - R0) * c * c * c * c * c;

            float P = .25f + .5f * Re;

            fs = pt.Diffuse.CloneValue().Mul(MathLab.INVPI).Mul((1f - Re) / (1f - P));
        }

        public override void Sample_f(ShadePointInfo pt, float u0, float u1, float u2, out Vector vector, out float radiancePdf,
            out float pdf1, out BsdfEvent @event)
        {

            float c = 1f - Vector.Dot(ref pt.IncomingDirection, ref pt.ShadingNormal);

            float Re = R0 + (1f - R0) * c * c * c * c * c;
            float P = .25f + .5f * Re;

            if ((u2 < P && reflectionSpecularBounce))
            {//onlySpecular || 
                vector = MetalBrdf.GlossyReflection(ref pt.IncomingDirection, exponent, ref pt.ShadingNormal, u0, u1);
                pdf1 = P / Re;
                @event = BsdfEvent.Specular;
                radiancePdf = Re;
            }
            else
            {
                Vector dir = MC.CosineSampleHemisphere(u0, u1);
                pdf1 = dir.z * MathLab.INVPI;

                /*
                Vector v1, v2;
                 * 
                dir =
                
                Vector.CoordinateSystem(ref shadeN, out v1, out v2);

                dir = new Vector(
                    v1.x * dir.x + v2.x * dir.y + shadeN.x * dir.z,
                    v1.y * dir.x + v2.y * dir.y + shadeN.y * dir.z,
                    v1.z * dir.x + v2.z * dir.y + shadeN.z * dir.z);*/
                ONB fm = new ONB(ref pt.ShadingNormal);

                var wi = fm.ToWorld(ref dir);//pt.Frame

                float dp = Vector.Dot(ref pt.ShadingNormal, ref wi);
                // Using 0.0001 instead of 0.0 to cut down fireflies
                if (dp <= 0.0001f)
                {
                    pdf1 = 0f;
                }
                pdf1 /= dp;

                float iRe = 1f - Re;
                pdf1 *= (1f - P) / iRe;
                @event = BsdfEvent.Glossy | BsdfEvent.Diffuse;
                vector = wi;
                radiancePdf = iRe;

            }
        }



        public override BrdfClass Class
        {
            get { return BrdfClass.Alloy; }
        }

        public override float Pdf(ref Vector wo, ref Vector wi)
        {
            throw new System.NotImplementedException();
        }
    }
}